﻿using IOA.MES.Client.Common;
using IOA.MES.Client.Models.Response;
using IOA.MES.Client.Settings;
using IOA.MES.Common;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
using System.Reflection;
using System.Net;
using System.Text;
using IOA.MES.Client.Models;

namespace IOA.MES.Client.EL1
{
    /// <summary>
    /// EL1Index.xaml 的交互逻辑
    /// </summary>
    public partial class EL1Index : Window
    {
        private WinEL1Tip winEL1Tip;
        private static bool isExcute = false;
        private static HttpListener listener = new HttpListener();
        private List<string> qLevels = new List<string>();
        private List<ViaSiteRecord> _records { get; set; } = new List<ViaSiteRecord>();
        private List<KeyValuePair<int, string>> fileChanges { get; set; } = new List<KeyValuePair<int, string>>();

        public EL1Index()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(BaseEnv.UserInfo.FtpConfig?.FtpRoot) || string.IsNullOrWhiteSpace(BaseEnv.UserInfo.FtpConfig?.UserName) || string.IsNullOrWhiteSpace(BaseEnv.UserInfo.FtpConfig?.Password))
            {
                CommonMessage.Alert(this, "请在系统设置中配置文件上传地址\r\nPlease configure the file upload address in the system settings", false);
            }

            txtTrueName.Text = BaseEnv.UserInfo.TrueName;

            winEL1Tip = new WinEL1Tip();
            winEL1Tip.Show();
            winEL1Tip.Topmost = true;

            InitDuties();
            InitMachines();
            InitQLevels();
            InitRecords();

            StartHttpListen();
        }


        #region 初始化数据
        public void InitDuties()
        {
            var duties = BaseEnv.InvokeApi<QueryDutiesResponse>("/api/Auth/QueryDuties", new { }).Data.Duties;

            cbDuties.ItemsSource = duties;
            cbDuties.DisplayMemberPath = "DutyName";
            cbDuties.SelectedValuePath = "DutyId";

            if (duties.Any())
            {
                cbDuties.SelectedIndex = 0;
            }
        }

        public void InitMachines()
        {
            var machines = BaseEnv.InvokeApi<QueryMachinesResponse>("/api/Machine/QueryMachines", new { MachineType = MachineType.EL1 }).Data.Machines;
            cbMachines.ItemsSource = machines;
            cbMachines.DisplayMemberPath = "MachineName";
            cbMachines.SelectedValuePath = "MachineId";

            if (machines.Any(_ => _.MachineId == BaseEnv.MachineId))
            {
                cbMachines.SelectedIndex = machines.FindIndex(_ => _.MachineId == BaseEnv.MachineId);
            }
            else
            {
                CommonMessage.Alert(this, "请先在系统设置中重新选择设备\r\nPlease reselect the device in the system settings now"); ;
                new SettingsIndex().ShowDialog();
            }
        }

        private void InitRecords()
        {
            new TaskFactory().StartNew(() =>
            {
                Thread.Sleep(100);
                Dispatcher.Invoke(new Action(() =>
                {
                    var response = BaseEnv.InvokeApi<QueryViaSiteRecordsResponse>("/api/Machine/QueryViaSiteRecords", new { DutyId = Convert.ToInt32(cbDuties.SelectedValue), SiteType = SiteType.EL1, MachineId = Convert.ToInt32(cbMachines.SelectedValue) });
                    if (response.ErrCode != 200)
                    {
                        CommonMessage.Alert(this, response.ErrMsg);
                        return;
                    }
                    _records.Clear();
                    _records.AddRange(response.Data.Records);
                    _records.ForEach(_ => _.No = _records.Count - _records.IndexOf(_));
                    BindGridRecords();
                }));
            });
        }

        private void BindGridFileChanges(string content)
        {
            fileChanges.Insert(0, new KeyValuePair<int, string>(fileChanges.Count + 1, content));
            gridFileChanges.ItemsSource = null;
            gridFileChanges.ItemsSource = fileChanges;
        }

        private void BindGridRecords()
        {
            gridRecords.ItemsSource = null;
            gridRecords.ItemsSource = _records;
            lbTotal.Content = _records.Select(_ => _.Code.ToUpper().Trim()).Distinct().Count();
        }

        public void InitQLevels()
        {
            qLevels = BaseEnv.InvokeApi<QueryQLevelsResponse>("/api/NQC/QueryLevels", new { }).Data.Levels;
            if (qLevels.Count < 2)
            {
                CommonMessage.Alert(this, "系统需要至少配置2个以上判定等级，请联系工艺人员\r\nThe system needs to be configured with at least two or more judgment levels, please contact the technical staff");
                Environment.Exit(0);
            }
        }

        /// <summary>
        /// 启动Http监听
        /// </summary>
        private void StartHttpListen()
        {
            new TaskFactory().StartNew(() =>
            {
                ExcuteHttp();
            });
        }
        #endregion

        private void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            InitRecords();
        }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (winEL1Tip != null && PresentationSource.FromVisual(winEL1Tip) != null)
            {
                winEL1Tip.Close();
            }
        }

        /// <summary>
        /// 启动Http监听
        /// </summary>
        private void ExcuteHttp()
        {
            listener.Prefixes.Clear();
            var httpRoot = BaseEnv.GetStorage("El1HttpRoot");
            httpRoot = !string.IsNullOrWhiteSpace(httpRoot) ? httpRoot : "http://127.0.0.1:1000/";
            listener.Prefixes.Add(httpRoot);
            listener.Start();
            isExcute = true;
            CommonMessage.Log(LogLevel.Warn, $"Http服务已启动（{httpRoot}）");
            while (isExcute)
            {
                try
                {
                    HttpListenerContext context = null;
                    try
                    {
                        context = listener.GetContext();
                    }
                    catch (Exception ex)
                    {
                        if (!isExcute)
                        {
                            return;
                        }

                        isExcute = false;
                        CommonMessage.Alert(this, $"Http服务已停止（{httpRoot}），请重新启动MES软件", true, ex);
                        return;
                    }

                    HttpListenerRequest request = context.Request;
                    var responseStr = string.Empty;
                    try
                    {
                        if (!string.Equals(request.HttpMethod, "POST", StringComparison.CurrentCultureIgnoreCase))
                        {
                            responseStr = JsonConvert.SerializeObject(new
                            {
                                Code = 400,
                                Message = "接口不支持GET请求",
                                HasError = true
                            });
                        }
                        else
                        {
                            var reader = new StreamReader(request.InputStream);
                            var bodyStr = reader.ReadToEnd();
                            CommonMessage.Log(LogLevel.Warn, $"接收到请求：\r\n{bodyStr}");
                            responseStr = JsonConvert.SerializeObject(new
                            {
                                Code = 0,
                                Message = "请求成功",
                                HasError = false
                            });
                            if (string.Equals(request.RawUrl, "/UploadResult", StringComparison.CurrentCultureIgnoreCase))
                            {
                                Dispatcher.Invoke(new Action(() =>
                                {
                                    UploadResult(bodyStr);
                                }));
                            }
                            else
                            {
                                responseStr = JsonConvert.SerializeObject(new
                                {
                                    Code = 403,
                                    Message = "请求地址无效",
                                    HasError = true
                                });
                            }
                            CommonMessage.Log(LogLevel.Warn, $"请求处理成功");
                        }
                    }
                    catch (Exception ex)
                    {
                        CommonMessage.Log(LogLevel.Fatal, "请求处理异常", ex);
                        responseStr = JsonConvert.SerializeObject(new
                        {
                            Code = 500,
                            Message = ex.Message,
                            HasError = true
                        });
                    }
                    CommonMessage.Log(LogLevel.Warn, $"返回请求：\r\n{responseStr}");

                    byte[] buffer = Encoding.UTF8.GetBytes(responseStr);
                    context.Response.ContentLength64 = buffer.Length;
                    context.Response.StatusCode = 200;
                    context.Response.ContentType = "application/json";
                    using (Stream output = context.Response.OutputStream)
                    {
                        output.Write(buffer, 0, buffer.Length);
                    }
                }
                catch (Exception ex)
                {
                    CommonMessage.Log(LogLevel.Fatal, "请求监听异常", ex);
                }
            }
        }

        /// <summary>
        /// 获取组件信息
        /// </summary>
        private Component GetComponent(string barCode)
        {
            var getComponentResponse = BaseEnv.InvokeApi<GetComponentResponse>("/api/Machine/GetComponent", new { BarCode = barCode });
            if (getComponentResponse.ErrCode != 200)
            {
                mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                mediaElResult.Play();
                throw new Exception(getComponentResponse.ErrMsg);
            }
            else if (getComponentResponse.Data == null || getComponentResponse.Data.Component == null)
            {
                mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                mediaElResult.Play();
                throw new Exception($"组件不存在\r\nComponent does not exist：\r\n{barCode}");
            }
            if (winEL1Tip != null && PresentationSource.FromVisual(winEL1Tip) != null)
            {
                winEL1Tip.SetComponent(getComponentResponse.Data.Component);
            }
            return getComponentResponse.Data.Component;
        }

        /// <summary>
        /// 上传EL结果
        /// </summary>
        private void UploadResult(string bodyStr)
        {
            var body = JsonConvert.DeserializeObject<ElResultRequest>(bodyStr);
            if (string.IsNullOrWhiteSpace(body.LotNumber))
            {
                throw new Exception("组件条码为空");
            }

            Thread.Sleep(3000);
            var elResult = new List<ElResult>();
            var component = GetComponent(body.LotNumber);
            //上传EL图片
            var ftpUtils = new FtpUtils(BaseEnv.UserInfo.FtpConfig.FtpRoot, BaseEnv.UserInfo.FtpConfig.UserName, BaseEnv.UserInfo.FtpConfig.Password);
            try
            {
                var elDirectory = $"/{BaseEnv.WorkshopCode}/el1/{component.WorkOrderNo}";
                ftpUtils.CheckAndCreateDirectory(elDirectory);
                var elFileName = $"{elDirectory}/{Path.GetFileName(body.ELImageFilePath)}";
                ftpUtils.Upload(File.ReadAllBytes(body.ELImageFilePath), elFileName);
                BindGridFileChanges($"图片上传完成：{body.ELImageFilePath}");
                elResult.Add(new ElResult
                {
                    Image = $"{BaseEnv.UserInfo.FtpConfig.FtpRoot}{elFileName}",
                    Positions = (body.ELTestResults ?? new List<ELResultItem>())
                        .Where(p => !string.Equals(p.Name, "OK", StringComparison.CurrentCultureIgnoreCase))
                        .Select(_ => new ElPosition
                        {
                            Name = _.Name,
                            Position = _.Position
                        }).ToList()
                });
            }
            catch (Exception ex)
            {
                throw new Exception($"EL图片上传失败：{ex.Message}");
            }

            //上传外观检图片
            try
            {
                var wgDirectory = $"/{BaseEnv.WorkshopCode}/wg1/{component.WorkOrderNo}";
                ftpUtils.CheckAndCreateDirectory(wgDirectory);
                var wgFileName = $"{wgDirectory}/{Path.GetFileName(body.VIImageFilePath)}";
                ftpUtils.Upload(File.ReadAllBytes(body.VIImageFilePath), wgFileName);
                BindGridFileChanges($"图片上传完成：{body.VIImageFilePath}");
                elResult.Add(new ElResult
                {
                    Image = $"{BaseEnv.UserInfo.FtpConfig.FtpRoot}{wgFileName}",
                    Positions = (body.VITestResults ?? new List<ELResultItem>())
                        .Where(p => !string.Equals(p.Name, "OK", StringComparison.CurrentCultureIgnoreCase))
                        .Select(_ => new ElPosition
                        {
                            Name = _.Name,
                            Position = _.Position
                        }).ToList()
                });
            }
            catch (Exception ex)
            {
                throw new Exception($"外观图片上传失败：{ex.Message}");
            }

            ViaSite(body.LotNumber, body.IsOK, elResult);
        }

        /// <summary>
        /// 过站
        /// </summary>
        private void ViaSite(string barCode, bool result, List<ElResult> elResult)
        {
            CommonMessage.Log(LogLevel.Info, $"条码：{txtCode.Text.Trim()}，结果：{result}，图片：{JsonConvert.SerializeObject(elResult)}");

            txtCode.Text = barCode;
            var viaSiteRequest = new
            {
                SiteType = (int)SiteType.EL1,
                DutyId = Convert.ToInt32(cbDuties.SelectedValue),
                MachineId = Convert.ToInt32(cbMachines.SelectedValue),
                Code = barCode,
                QLevel = result ? qLevels[0] : qLevels[1],
                ElResults = elResult,
            };

            var response = BaseEnv.InvokeApi<ViaSiteResponse>("/api/Machine/ViaSite", viaSiteRequest);
            if (response.ErrCode != 200)
            {
                mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                mediaElResult.Play();
                CommonMessage.Alert(this, response.ErrMsg, false);
                return;
            }

            mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Success.wav");
            mediaElResult.Play();

            CommonMessage.Log(LogLevel.Info, $"过站成功：{txtCode.Text.Trim()}");

            if (response.Data.DutyId != Convert.ToInt32(cbDuties.SelectedValue))
            {
                cbDuties.SelectedValue = response.Data.DutyId;
            }
            else
            {
                response.Data.ViaSiteRecord.No = _records.Count + 1;
                _records.Insert(0, response.Data.ViaSiteRecord);
                BindGridRecords();
            }
        }

        private void Menu_Click(object sender, RoutedEventArgs e)
        {
            switch (((MenuItem)sender).Name)
            {
                case "btnSettings":
                    new SettingsIndex().ShowDialog();
                    break;
                case "btnDeviceSettings":
                    if (new WinElSettings().ShowDialog() == true)
                    {
                        StartHttpListen();
                    }
                    break;
                case "btnMissingRecords":
                    new MissingSiteRecord(Convert.ToInt32(cbMachines.SelectedValue)).Show();
                    break;
                case "btnLogout":
                    new LoginWindow(false).Show();
                    this.Hide();
                    break;
                case "btnAbout":
                    MessageBox.Show($"AISUNMes Product Version:{FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion}");
                    break;
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            if (listener != null)
            {
                isExcute = false;
                listener.Close();
            }
            Environment.Exit(0);
        }
    }
}
